package com.hccake.ballcat.codegen.util;

import cn.hutool.core.codec.Base64;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.*;

/**
 * @author hccake
 */
@Slf4j
public final class GitLabUtil {

	private static String GITLAB_SINGLE_PROJECT_API = "/api/v3/projects?private_token=#{PRIVATE_TOKEN}";

	private static String GITLAB_FILECONTENT_API = "/api/v3/projects/#{PROJECT_ID}/repository/files"
			+ "?private_token=#{PRIVATE_TOKEN}&file_path=#{FILE_PATH}&ref=#{BRANCH_NAME}";

	private static String GITLAB_GET_FILE_BY_FOLDER_API = "/api/v3/projects/#{PROJECT_ID}/repository/tree"
			+ "?private_token=#{PRIVATE_TOKEN}&path=#{FOLDER_PATH}&ref=#{BRANCH_NAME}";

	/**
	 * 使用gitLab api获取指定项目的projectId，为Get请求
	 * @param ip 项目仓库的ip地址
	 * @param projectPath
	 * 项目的path，如：http://192.168.59.185/acountting/dispatcher-cloud.git，则projectPath为：acountting/dispatcher-cloud
	 * @param privateToken 用户个人访问gitlab库时的privateToken，可以通过{@link #}获取
	 * @return 返回目的projectId
	 */
	public static JSONObject getProjectId(String ip, String projectPath, String privateToken) {
		/** 1.参数替换，生成访问获取project信息的uri地址 */
		// 校验参数
		Objects.requireNonNull(ip, "参数ip不能为空！");
		Objects.requireNonNull(projectPath, "参数projectPath不能为空！");
		Objects.requireNonNull(privateToken, "参数privateToken不能为空！");
		// 参数准备，存入map
		Map<String, String> params = new HashMap<String, String>(4);
		params.put("REPO_IP", ip);
		params.put("PRIVATE_TOKEN", privateToken);
		// gitlab api要求项目的path需要安装uri编码格式进行编码，比如"/"编码为"%2F"
		try {
			params.put("PROJECT_PATH", URLEncoder.encode(projectPath, "UTF-8"));
		}
		catch (UnsupportedEncodingException e) {
			throw new RuntimeException(String.format("对%s进行URI编码出错！", projectPath));
		}
		// 调用工具类替换,得到具体的调用地址
		String getSingleProjectUrl = PlaceholderUtil.anotherReplace(ip + GITLAB_SINGLE_PROJECT_API, params);
		log.debug(String.format("获取projectId的url：%s", getSingleProjectUrl));

		// 创建URI对象
		URI url = null;
		try {
			url = new URI(getSingleProjectUrl);
		}
		catch (URISyntaxException e) {
			throw new RuntimeException(String.format("使用%s创建URI出错！", getSingleProjectUrl));
		}

		/** 2.访问url，获取制定project的信息 */
		RestTemplate restTemplate = new RestTemplate();
		ResponseEntity<String> reslut = restTemplate.getForEntity(url, String.class);
		log.debug(String.format("响应头为：%s，响应体为：%s", reslut.getHeaders(), reslut.getBody()));

		/** 3.解析结果 */
		if (reslut.getStatusCode() != HttpStatus.OK) {
			throw new RuntimeException(String.format("请求%s出错！错误码为：%s", url, reslut.getStatusCode()));
		}
		// 如果响应码是200，说明正常拿到响应结果，解析出projectId返回即可
		JSONArray responArr = JSON.parseArray(reslut.getBody());
		JSONObject jsonObject = null;
		if (null != responArr && responArr.size() > 0) {
			for (Object o : responArr) {
				JSONObject responBody = (JSONObject) o;
				String projectRepo = responBody.getString("path_with_namespace");
				if (projectRepo.length() > 0 && projectPath.contains(projectRepo)) {
					/*
					 * projectId = responBody.getString("id"); name =
					 * responBody.getString("name");
					 */
					jsonObject = responBody;
					break;
				}
			}
		}

		/** 4.返回projectId */
		return jsonObject;
	}

	public static String getFileContentFromRepository(String ip, String projectPath, String branchName,
			String privateToken) throws Exception {
		// 校验参数
		Objects.requireNonNull(ip, "参数ip不能为空！");
		Objects.requireNonNull(projectPath, "参数gitPath不能为空！");
		Objects.requireNonNull(branchName, "参数分支不能为空！");

		/** 2.使用privateToken获取项目的projectId */
		JSONObject projectObj = getProjectId(ip, projectPath, privateToken);
		String projectId = projectObj.getString("id");
		String fileFullPath = projectPath.substring(projectPath.indexOf(projectObj.getString("path_with_namespace"))
				+ projectObj.getString("path_with_namespace").length() + 1);

		/** 3.使用参数替换形成请求git库中文件内容的uri */
		// 参数准备，存入map
		Map<String, String> params = new HashMap<String, String>(4);
		params.put("REPO_IP", ip);
		params.put("PROJECT_ID", projectId);
		params.put("PRIVATE_TOKEN", privateToken);
		params.put("FILE_PATH", fileFullPath);
		params.put("BRANCH_NAME", branchName);
		// 使用工具类替换参数
		String reqFileCotnetUri = PlaceholderUtil.anotherReplace(ip + GITLAB_FILECONTENT_API, params);
		log.debug(String.format("获取文件：%s的uri：%s", fileFullPath, reqFileCotnetUri));

		/** 4.请求gitlab获取文件内容 */
		RestTemplate restTemplate = new RestTemplate();
		ResponseEntity<String> response = restTemplate.getForEntity(reqFileCotnetUri, String.class);
		log.debug(String.format("响应头为：%s，响应体为：%s", response.getHeaders(), response.getBody()));

		/** 5.解析响应结果内容 */
		String body = response.getBody();
		JSONObject jsonBody = JSON.parseObject(body);
		String fileName = jsonBody.getString("file_name");
		String filePath = jsonBody.getString("file_path");
		String encoding = jsonBody.getString("encoding");
		String content = jsonBody.getString("content");
		String commitId = jsonBody.getString("commit_id");
		String lastCommitId = jsonBody.getString("last_commit_id");

		// 内容已经base64编码，如果需要获取原始文件内容可以参看api：https://docs.gitlab.com/ee/api/repository_files.html#get-raw-file-from-repository
		content = new String(Base64.decode(content), "UTF-8");

		log.debug(String.format(
				"获取http://%s 上%s项目 %s分支的%s文件,响应信息是:fileName :%s ,filePath:%s , 编码：%s ,内容:%s , commitId:%s ,lastCommitId :%s",
				ip, projectPath, branchName, fileFullPath, fileName, filePath, encoding, content, commitId,
				lastCommitId));

		/** 6.返回指定文件的内容 */
		log.debug(String.format("解析得到文件内容为：%s", content));
		return content;
	}

	public static List<String> getFilePathByFolderRepository(String ip, String folderPath, String branchName,
			String privateToken) {
		// 校验参数
		Objects.requireNonNull(ip, "参数ip不能为空！");
		Objects.requireNonNull(folderPath, "参数gitPath不能为空！");
		Objects.requireNonNull(branchName, "参数分支不能为空！");

		/** 2.使用privateToken获取项目的projectId */
		JSONObject projectObj = getProjectId(ip, folderPath, privateToken);
		String projectId = projectObj.getString("id");
		String folderFullPath = folderPath.substring(folderPath.indexOf(projectObj.getString("path_with_namespace"))
				+ projectObj.getString("path_with_namespace").length() + 1);

		/** 3.使用参数替换形成请求git库中文件内容的uri */
		// 参数准备，存入map
		Map<String, String> params = new HashMap<String, String>(4);
		params.put("REPO_IP", ip);
		params.put("PROJECT_ID", projectId);
		params.put("PRIVATE_TOKEN", privateToken);
		params.put("FOLDER_PATH", folderFullPath);
		params.put("BRANCH_NAME", branchName);
		// 使用工具类替换参数
		String reqFileFolderUri = PlaceholderUtil.anotherReplace(ip + GITLAB_GET_FILE_BY_FOLDER_API, params);
		log.debug(String.format("获取文件：%s的uri：%s", folderFullPath, reqFileFolderUri));

		/** 4.请求gitlab获取文件夹下面所有文件 */
		RestTemplate restTemplate = new RestTemplate();
		ResponseEntity<String> response = restTemplate.getForEntity(reqFileFolderUri, String.class);
		log.debug(String.format("响应头为：%s，响应体为：%s", response.getHeaders(), response.getBody()));

		/** 5.接口文件加，并且返回 */
		List<String> rsList = new ArrayList<>();
		String body = response.getBody();
		JSONArray jsonBodyArr = JSON.parseArray(body);
		if (null != jsonBodyArr && jsonBodyArr.size() > 0) {
			for (Object o : jsonBodyArr) {
				JSONObject temp = (JSONObject) o;
				String path = temp.getString("path");
				path = path.replaceFirst(folderFullPath, "");
				rsList.add(folderPath + path);
			}
		}

		return rsList;
	}

	public static void main(String[] args) {
		try {
			List<String> fileContent = getFilePathByFolderRepository("http://119.12.173.113:8186",
					"http://119.12.173.113:8186/East-China-delivery-center/Cheryfs-Center-Platform/code/actm/base-bosent-alm/alm/config",
					"master", "buNXD4WtVfNXjUZuBET_");

			log.info("fileContent = " + fileContent);
		}
		catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
